package org.spring.springboot.socket;

import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DeviceMessage {
    private static final String HEADER = "LDCT";
    @Getter @Setter private String deviceType;
    @Getter @Setter private String deviceID;        // 12 digits
    @Getter @Setter private String commandType;
    @Getter @Setter private ArrayList<String> args;

    // device types
    public static final String GAS_HEATER = "01";               // 燃气热水器
    public static final String ELECTRIC_HEATER = "02";          // 储水式电热水器
    public static final String HEAT_PUMP = "03";                // 空气能热水器
    public static final String HANGING_FURNACE = "04";          // 壁挂炉
    public static final String SOLAR_HEATER = "05";             // 太阳能

    // command types
    public static String HEART_BEAT = "xtpc";             // 心跳包

    public DeviceMessage() {}

    public DeviceMessage(String message) {
        parse(message);
    }

    public DeviceMessage(String deviceType, String deviceID, String commandType) {
        this.deviceType = deviceType;
        this.deviceID = deviceID;
        this.commandType = commandType;
    }

    public DeviceMessage(String deviceType, String deviceID, String commandType, ArrayList<String> args) {
        this.deviceType = deviceType;
        this.deviceID = deviceID;
        this.commandType = commandType;
        this.args = new ArrayList<>(args);
    }

    public DeviceMessage(String deviceNum, String commandType, ArrayList<String> args) {

        // LDCT01201704230001
        this.deviceType = deviceNum.substring(4, 5);
        this.deviceID = deviceNum.substring(6, 17);
        this.commandType = commandType;
        this.args = new ArrayList<>(args);
    }

    public void setMessageString(String message) {
        parse(message);
    }

    // <LDCT01201704230001:xtds,052,2017,05,02,20,12,38,91>
    @Override
    public String toString() {
        return "<" + body() + checksum() + ">";
    }

    private String body() {
        return HEADER + deviceType + deviceID + ":" + commandType + "," + length() + argString() + ",";
    }

    private String argString() {
        if(args != null && !args.isEmpty()) {
             return "," + StringUtils.join(args, ",");
        } else {
            return "";
        }
    }

    private String length() {
        Integer len = 28;
        len += commandType.length();
        if(args != null && !args.isEmpty()) {
            for(String arg : args) {
                len += arg.length() + 1;
            }
        }
        return String.format("%03d", len);
    }

    private String checksum() {
        int sum = 0;
        for(char c: body().toCharArray()) {
            sum += (int)c;
        }
        String hex = Integer.toHexString(sum).toUpperCase();
        return hex.substring(hex.length() - 2);
    }


    private void parse(String message){
        if (StringUtils.isNotEmpty(message)) {
            // <LDCT01201704230001:xtds,052,2017,05,02,20,12,38,91>
            // <LDCT01201704230002:scyc,060,0000,00,00,20,00,00,000,0,0,0,0,0,0,0,0,FD>
            // LDCT                      : fixed header
            // 01                        : device type
            // 201704230001              : device id
            // xtds                      : command type
            // 052                       : command length
            // 2017,05,02,20,12,38       : args
            // 91                        : checksum

            Pattern pattern = Pattern.compile("(?<=LDCT)(\\d{2})(\\d{12}):(\\w+),(\\d{3})([,\\w+]*),(\\w{2})(?=>)");
            Matcher matcher = pattern.matcher(message);

            if(!matcher.find()) {
                return;
            }
            deviceType = matcher.group(1);
            deviceID = matcher.group(2);
            commandType = matcher.group(3);

            // if args
            // ",2017,05,02,20,12,38"
            if (StringUtils.isNotEmpty(matcher.group(5))) {
                args = new ArrayList<>(Arrays.asList(matcher.group(5).substring(1).split(",")));
            }
        }
    }


    public static void main(String[] args) {
        String m1_s = "<LDCT01201704230001:xtpc,032,C2>";
        String m2_s = "<LDCT01201704230001:xtds,052,2017,05,02,20,12,38,91>";

        DeviceMessage m1 = new DeviceMessage(m1_s);
        System.out.println(m1.toString().equals(m1_s));
        System.out.println(m1.getDeviceID().equals("201704230001"));

        DeviceMessage m2 = new DeviceMessage(m2_s);
        System.out.println(m2.getDeviceID().equals("201704230001"));

        DeviceMessage m3 = new DeviceMessage("01", "201704230001", "roty");
        System.out.println(m3.toString().equals("<LDCT01201704230001:roty,032,D1>"));


        // <LDCT01201704230001:romd,051,01,00,00000,004,OK,71>
        ArrayList<String> arg = new ArrayList<>();
        arg.add("01");
        arg.add("00");
        arg.add("00000");
        arg.add("004");
        arg.add("OK");

        DeviceMessage m4 = new DeviceMessage("01", "201704230001", "romd", arg);
        System.out.println(m4.toString().equals("<LDCT01201704230001:romd,051,01,00,00000,004,OK,71>"));
    }
}
